package com.settlement.system.common.util;

import cn.hutool.core.util.StrUtil;
import com.settlement.system.common.constant.SecurityConstants;
import com.settlement.system.common.result.Result;
import jakarta.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.util.Objects;

/**
 * 请求工具类
 *
 * @author haoxr
 */
public class RequestUtils {

    private static final Logger logger = LoggerFactory.getLogger(RequestUtils.class);
    /**
     * 请求头解析获取 Token
     */
    public static String resolveToken(HttpServletRequest request) {
        String bearerToken = request.getHeader(SecurityConstants.TOKEN_KEY);
        if (StrUtil.isNotBlank(bearerToken) && bearerToken.startsWith(SecurityConstants.TOKEN_PREFIX)) {
            return bearerToken.substring(SecurityConstants.TOKEN_PREFIX.length());
        }
        return null;
    }

    /**
     * 检查验签是否合法
     */
    public static Result<?> resolveAppToken(HttpServletRequest request, String secret, String appId) {
        String appIdParams = request.getParameter("appId");
        String sign = request.getParameter("sign");
        if (!StringUtils.hasText(sign)) {
            return Result.failed("签名失败");
        }
        if(!Objects.equals(appIdParams, appId)){
            return Result.failed("签名失败");
        }
        String timestamp = request.getParameter("timestamp");
        // 时间戳要为13位的毫秒级时间戳
        if (timestamp.length() != 13) {
            return Result.failed("签名失败");
        }
        //check时间戳的值是否在当前时间戳前后一30秒以内
        String currTimestamp = String.valueOf(System.currentTimeMillis());
        long currTimestampNum = Long.parseLong(currTimestamp);
        long verifyTimestampNum;
        try {
            verifyTimestampNum = Long.parseLong(timestamp);
        } catch (NumberFormatException e) {
            return Result.failed("签名失败");
        }
        // 在60秒范围之外，访问已过期
        if (Math.abs(verifyTimestampNum - currTimestampNum) > 1000 * 60) {
            return Result.failed("签名失败");
        }
        if (sign.equals(getSign(appId + timestamp, secret))) {
            return Result.success();
        }
        return Result.failed("签名失败");
    }

    /**
     * 得到签名
     *
     * @param content 参数集合,不含密钥secret
     * @param secret  分配的密钥secret
     * @return sign 签名
     */
    private static String getSign(String content, String secret) {
        byte[] md5Digest;
        // Md5加密得到sign
        md5Digest = getMd5Digest(content + secret);
        return byte2hex(md5Digest);
    }

    /**
     * 获取md5信息摘要
     *
     * @param data 需要加密的字符串
     * @return bytes 字节数组
     */
    private static byte[] getMd5Digest(String data) {
        byte[] bytes = null;
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            bytes = md.digest(data.getBytes(StandardCharsets.UTF_8));
        } catch (GeneralSecurityException gse) {
            logger.error("生成签名错误", gse);
        }
        return bytes;
    }

    /**
     * 将字节数组转化为16进制
     *
     * @param bytes 字节数组
     * @return sign 签名
     */
    private static String byte2hex(byte[] bytes) {
        StringBuilder sign = new StringBuilder();
        for (byte aByte : bytes) {
            String hex = Integer.toHexString(aByte & 0xFF);
            if (hex.length() == 1) {
                sign.append("0");
            }
            sign.append(hex.toUpperCase());
        }
        return sign.toString();
    }
}
